<?php

use Workerman\Worker;

include __DIR__ . '/vendor/autoload.php';

// 初始化一个worker容器，监听1234端口
global $worker;

$worker = new Worker('websocket://0.0.0.0:2122');

// 这里进程数必须设置为1
$worker->count = 1;

// 新增加一个属性，用来保存uid到connection的映射
$worker->uidConnections = array();

// worker进程启动后建立一个内部通讯端口
$worker->onWorkerStart = function ($worker) {

    // 开启一个内部端口，方便内部系统推送数据，Text协议格式 文本+换行符
    $inner_text_worker = new Worker('Text://0.0.0.0:2123');
    $inner_text_worker->onMessage = function ($connection, $buffer) {
        global $worker;

        // $data数组格式
        $data = json_decode($buffer, true);

        switch (@$data['type']) {
            case 'check':
                if (isset($data['content']) && $data['content']) {

                    $ret = [
                        'code' => 1,
                        'msg' => ''
                    ];
                    foreach ($data['content'] as $key => $value) {
                        if (isset($_SESSION[$value]) && isset($worker->uidConnections[$_SESSION[$value]])) {
                            $ret['data'][$value] = 1;
                        } else {
                            $ret['data'][$value] = 0;
                        }
                    }
                } else {
                    $ret = [
                        'code' => 0,
                        'msg' => '参数错误'
                    ];
                }
                $connection->send(json_encode($ret));
                break;
            case 'publish':
                // 如果没有要发送的人 直接返回失败
                if (!@$data['to']) {
                    return $connection->send(json_encode(['code' => 0, 'msg' => '没有接收人']));
                }

                if ('all' == $data['to']) {
                    $ret = broadcast($data['content']);
                } else {
                    $ret = sendMessageByUid($data['to'], $data['content']);
                }

                // 返回推送结果
                $connection->send($ret ? 1 : 0);
                break;
        }


    };
    $inner_text_worker->listen();
};

// 当有客户端发来消息时执行的回调函数
$worker->onMessage = function ($connection, $buffer) use ($worker) {

    $data = json_decode($buffer, true);

    if ('login' != @$data['type'] && !isset($connection->uid))
        return $connection->send(json_encode(['code' => 0, 'type' => 'login', 'msg' => '请先登录']));

    switch (@$data['type']) {
        case 'login' :
            // 判断当前客户端是否已经验证,既是否设置了uid
            if (isset($connection->uid))
                return $connection->send(json_encode(['code' => 0, 'type' => 'login', 'msg' => '您已经登录过了, 请勿重复登录']));
            if (!@$data['uid'])
                return $connection->send(json_encode(['code' => 0, 'type' => 'login', 'msg' => '登录失败, 缺少uid']));

            if (isset($_SESSION[$data['uid']])) {
                sendMessageByUid($data['uid'], '您已在其他设备上登录', 'logout');
                unset($worker->uidConnections[$_SESSION[$data['uid']]]);
            }

            $connection->uid = $_SESSION[$data['uid']] = $data['uid'] . time();
            $worker->uidConnections[$connection->uid] = $connection;
            return $connection->send(json_encode(['code' => 1, 'type' => 'login', 'msg' => '登录成功']));

            break;
        case 'publish':
            $result = ['code' => 0, 'type' => 'publish', 'msg' => '发送失败'];
            if (isset($data['to']) && $data['to']) {
                if (isset($_SESSION[$data['to']])) {
                    //$ret = sendMessageByUid($_SESSION[$data['to']], $data['content']);
                    $ret = sendMessageByUid($data['to'], $data['content']);
                    if ($ret) {
                        $result = ['code' => 1, 'type' => 'publish', 'msg' => '发送成功'];
                    }
                }
            }
            return $connection->send(json_encode($result));
            break;
        case 'ping' :
            if (!isset($connection->uid) || !isset($worker->uidConnections[$connection->uid])) {
                return $connection->send(json_encode(['code' => 0, 'type' => 'login', 'msg' => '请先登录']));
            }
            return $connection->send(json_encode(['code' => 1, 'type' => 'ping', 'msg' => 'ok']));
            break;
        case 'check':
            if (isset($data['content']) && $data['content']) {
                $ret = [
                    'code' => 1,
                    'msg' => ''
                ];
                foreach ($data['content'] as $key => $value) {
                    if (isset($_SESSION[$value]) && isset($worker->uidConnections[$_SESSION[$value]])) {
                        $ret['data'][$value] = 1;
                    } else {
                        $ret['data'][$value] = 0;
                    }
                }
            } else {
                $ret = [
                    'code' => 0,
                    'msg' => '参数错误'
                ];
            }
            $connection->send(json_encode($ret));
            break;
    }
};

// 当有客户端连接断开时
$worker->onClose = function ($connection) use ($worker) {
    global $worker;
    if (isset($connection->uid)) {
        // 连接断开时删除映射
        unset($worker->uidConnections[$connection->uid]);
    }
};

// 向所有验证的用户推送数据
function broadcast($content)
{
    global $worker;
    foreach ($worker->uidConnections as $connection) {
        $connection->send(json_encode([
            'type' => 'publish',
            'content' => $content
        ]));
    }
    return true;
}

// 针对uid推送数据
function sendMessageByUid($uids, $content, $type = 'publish')
{
    global $worker;
    if (!is_array($uids)) {
        $uids = explode(',', $uids);
    }
    $ret = false;
    foreach ($uids as $uid) {
        if (isset($_SESSION[$uid]) && isset($worker->uidConnections[$_SESSION[$uid]])) {
            $connection = $worker->uidConnections[$_SESSION[$uid]];
            $connection->send(json_encode([
                'type' => $type,
                'content' => $content
            ]));
            $ret = true;
        }
    }

    return $ret;
}

// 运行所有的worker（其实当前只定义了一个）
if (!defined('GLOBAL_START')) {
    Worker::runAll();
}

